﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using Compiler.CompilerLogic;
using Compiler.LabLogic;

namespace Compiler.LabForms
{
    public partial class MainForm : Form
    {
        private static MainForm _mainForm;

        private MainForm()
        {
            InitializeComponent();
        }

        private void DisableCodePage()
        {
            panel4.Enabled = false;
        }

        private void DisableLexicalPage()
        {
            panel1.Enabled = false;
            panel2.Enabled = false;
            panel3.Enabled = false;
            checkLexical.Enabled = false;
            tokensView.AllowDrop = false;
            idsView.AllowDrop = false;
            constantsView.AllowDrop = false;
        }

        private void DisableSyntaxPage()
        {
            panel8.Enabled = false;
            button4.Enabled = false;
        }

        private void DisableTetradesPanel()
        {
            panel9.Enabled = false;
            checkTetrades.Enabled = false;
            tetradesView.AllowDrop = false;
        }

        private void EnableCodePage()
        {
            panel4.Enabled = true;
        }

        private void EnableLexicalPage()
        {
            panel1.Enabled = true;
            panel2.Enabled = true;
            panel3.Enabled = true;
            checkLexical.Enabled = true;
            tokensView.AllowDrop = true;
            idsView.AllowDrop = true;
            constantsView.AllowDrop = true;
        }

        private void EnableSyntaxPage()
        {
            panel8.Enabled = true;
            button4.Enabled = true;
        }

        private void EnableTetradesPanel()
        {
            panel9.Enabled = true;
            checkTetrades.Enabled = true;
            tetradesView.AllowDrop = true;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            DisableLexicalPage();
            DisableSyntaxPage();
            DisableTetradesPanel();
        }

        public static MainForm GetMainForm()
        {
            return _mainForm ?? (_mainForm = new MainForm());
        }

        public TabControl GetTabControl()
        {
            return tabControl;
        }

        public void EnableMenuLinks()
        {
            saveLabLink.Enabled = true;
            saveLabAsLink.Enabled = true;
            menuLab.Enabled = true;
            loadCodeLink.Enabled = true;
        }

        public void QuickStartMessages()
        {
            var messages = new List<string>
            {
                "",
                "Новая лабораторная работа",
                "",
                "",
                "Ответьте на 12 вопросов теста (Работа - Тестирование)",
                "",
                "Начните выполнение компиляции, загрузив файл с кодом программы (Работа - Загрузить код программы)"
            };
            LoadLabModel(new LabModel());
            codeBox.Lines = messages.ToArray();
            checkCode.Visible = false;
            codeBox.Enabled = false;
            codePage.Text = @"Начало работы";
            codeBox.TextAlign = HorizontalAlignment.Center;
            codeBox.Font = new Font("Consolas", 14.25F, FontStyle.Italic, GraphicsUnit.Point, 204);
        }

        public void AssemblyLabModel()
        {
            var labModel = new LabModel
            {
                CodeLoaded = loadCodeLink.Enabled,
                CodePageHeader = codePage.Text,
                CodeBoxLines = codeBox.Lines,
                CodeBoxFont = codeBox.Font,
                CodeScrollbars = codeBox.ScrollBars == ScrollBars.Both,
                CodeBoxEnabled = codeBox.Enabled,
                CodeBoxAlignment = codeBox.TextAlign,
                CodeEnabled = panel4.Enabled,
                CheckCodeVisible = checkCode.Visible,
                LexicalEnabled = panel1.Enabled,
                SyntaxEnabled = panel8.Enabled,
                TetradesEnabled = panel9.Enabled,
            };
            foreach (ListViewItem item in tokensView.Items)
            {
                labModel.Tokens.Add(new TokenModel(item.ImageIndex, item.Text, item.ToolTipText));
            }
            foreach (ListViewItem item in idsView.Items)
            {
                labModel.Identifiers.Add(new IdentifierModel(item.Text, item.SubItems[1].Text, item.SubItems[2].Text, item.SubItems[3].Text));
            }
            foreach (ListViewItem item in constantsView.Items)
            {
                labModel.Constants.Add(new ConstantModel(item.Text, item.SubItems[1].Text));
            }

            labModel.TreeRoot = new SyntaxNode(GetNodeName(treeBuilder.Nodes[0].Text), GetNodeValue(treeBuilder.Nodes[0].Text), null);
            foreach (TreeNode treeNode in treeBuilder.Nodes[0].Nodes)
            {
                AddChildSyntaxNode(treeNode, labModel.TreeRoot);
            }

            foreach (ListViewItem item in tetradesView.Items)
            {
                labModel.Tetrades.Add(new TetradeModel(item.Text, item.SubItems[1].Text, item.SubItems[1].Text, item.SubItems[1].Text));
            }

            if (assembleCode.Lines.Length > 0)
            {
                for (int i = 0; i < assembleCode.Lines.Length; i++)
                {
                    labModel.AssemblyCodeLines.Add(assembleCode.Lines[i]);
                }
            }
            Lab.GetLab().StoreLabModel(labModel);
        }

        public void LoadLabModel(LabModel labModel)
        {
            loadCodeLink.Enabled = labModel.CodeLoaded;
            codePage.Text = labModel.CodePageHeader;
            codeBox.Lines = labModel.CodeBoxLines;
            codeBox.Font = labModel.CodeBoxFont;
            codeBox.Enabled = labModel.CodeBoxEnabled;
            codeBox.TextAlign = labModel.CodeBoxAlignment;
            codeBox.ScrollBars = labModel.CodeScrollbars ? ScrollBars.Both : ScrollBars.None;
            if (labModel.CodeEnabled) EnableCodePage(); else DisableCodePage();
            checkCode.Visible = labModel.CheckCodeVisible;
            codeLexicalBox.Lines = labModel.CodeBoxLines;
            if (labModel.LexicalEnabled) EnableLexicalPage(); else DisableLexicalPage();
            if (labModel.SyntaxEnabled) EnableSyntaxPage(); else DisableSyntaxPage();
            if (labModel.TetradesEnabled) EnableTetradesPanel(); else DisableTetradesPanel();

            tokensView.Items.Clear();
            foreach (var token in labModel.Tokens)
            {
                var newItem = new ListViewItem
                {
                    Text = token.Value,
                    ToolTipText = token.ToolTipText,
                    ImageIndex = token.ImageIndex
                };
                tokensView.Items.Add(newItem);
            }

            idsView.Items.Clear();
            foreach (var identifier in labModel.Identifiers)
            {
                var newItem = new ListViewItem
                {
                    Text = identifier.Id,
                };
                newItem.SubItems.Add(identifier.Value);
                newItem.SubItems.Add(identifier.Type);
                newItem.SubItems.Add(identifier.Level);
                idsView.Items.Add(newItem);
            }

            constantsView.Items.Clear();
            foreach (var constant in labModel.Constants)
            {
                var newItem = new ListViewItem
                {
                    Text = constant.Id,
                };
                newItem.SubItems.Add(constant.Value);
                constantsView.Items.Add(newItem);
            }

            tokensViewOnly.Items.Clear();
            constantsViewOnly.Items.Clear();
            identsViewOnly.Items.Clear();
            if (Lab.GetLab().LexicalComplete)
            {
                foreach (ListViewItem item in tokensView.Items)
                {
                    tokensViewOnly.Items.Add((ListViewItem)item.Clone());
                }
                foreach (ListViewItem item in constantsView.Items)
                {
                    constantsViewOnly.Items.Add((ListViewItem)item.Clone());
                }
                foreach (ListViewItem item in idsView.Items)
                {
                    identsViewOnly.Items.Add((ListViewItem)item.Clone());
                }
            }

            var root = new TreeNode(labModel.TreeRoot.NodeName + ": " + labModel.TreeRoot.NodeVal);
            foreach (SyntaxNode syntaxNode in labModel.TreeRoot.ChildNodes)
            {
                AddChildTreeNode(syntaxNode, root);
            }
            treeBuilder.Nodes.Clear();
            treeBuilder.Nodes.Add(root);
            root.ExpandAll();
            if (Lab.GetLab().SyntaxComplete)
            {
                treeView.Nodes.Clear();
                treeView.Nodes.Add((TreeNode) root.Clone());
                treeView.Nodes[0].ExpandAll();
            }

            tetradesView.Items.Clear();
            foreach (var tetrade in labModel.Tetrades)
            {
                var newItem = new ListViewItem
                {
                    Text = tetrade.Operation
                };
                newItem.SubItems.Add(tetrade.OperandOne);
                newItem.SubItems.Add(tetrade.OperandTwo);
                newItem.SubItems.Add(tetrade.Operation);
                tetradesView.Items.Add(newItem);
            }

            assembleCode.Clear();
            assembleCode.Lines = labModel.AssemblyCodeLines.ToArray();
        }

        private void exitLabLink_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void newLabLink_Click(object sender, EventArgs e)
        {
            if (Lab.GetLab() != null)
            {
                DialogResult dialogResult =
                    MessageBox.Show(
                        @"Все несохраненные данные текущей работы будут утеряны. Вы действительно хотите начать новую работу?",
                        @"Внимание",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (dialogResult == DialogResult.Yes)
                {
                    var userForm = new UserForm();
                    userForm.ShowDialog();
                }
            }
            else
            {
                var userForm = new UserForm();
                userForm.ShowDialog();
            }
        }

        private void testResultsLink_Click(object sender, EventArgs e)
        {
            var testForm = new TestForm();
            testForm.ShowDialog();
        }

        private void saveLabAsLink_Click(object sender, EventArgs e)
        {
            var saveFileDialog = new SaveFileDialog
            {
                Filter = @"Файл лабораторной работы C mini (*.cml) | *.cml",
                Title = @"Сохранение лабораторной работы",
                ValidateNames = true
            };
            if (saveFileDialog.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(saveFileDialog.FileName))
            {
                var fs = (FileStream) saveFileDialog.OpenFile();
                var bf = new BinaryFormatter();
                Lab.GetLab().FileName = saveFileDialog.FileName;
                AssemblyLabModel();
                Text = @"Компилятор C mini - " + Lab.GetLab().FileName;
                bf.Serialize(fs, Lab.GetLab());
                fs.Close();
            }
            
        }

        private void loadLabLink_Click(object sender, EventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Filter = @"Файл лабораторной работы C mini (*.cml) | *.cml",
                Title = @"Загрузка лабораторной работы",
                Multiselect = false,
                ValidateNames = true
            };

            if (Lab.GetLab() != null)
            {
                DialogResult dialogResult =
                    MessageBox.Show(
                        @"Все несохраненные данные текущей работы будут утеряны. Вы действительно хотите загрузить другую работу?",
                        @"Внимание",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (dialogResult == DialogResult.Yes)
                {
                    if (openFileDialog.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(openFileDialog.FileName))
                    {
                        var fs = (FileStream) openFileDialog.OpenFile();
                        var bf = new BinaryFormatter();
                        Lab.LoadLab((Lab)bf.Deserialize(fs));
                        LoadLabModel(Lab.GetLab().GetLabModel());
                        Text = @"Компилятор C mini - " + Lab.GetLab().FileName;
                        fs.Close();
                        saveLabLink.Enabled = true;
                        saveLabAsLink.Enabled = true;
                        menuLab.Enabled = true;
                    }
                }
            }
            else
            {
                if (openFileDialog.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(openFileDialog.FileName))
                {
                    var fs = (FileStream)openFileDialog.OpenFile();
                    var bf = new BinaryFormatter();
                    Lab.LoadLab((Lab)bf.Deserialize(fs));
                    LoadLabModel(Lab.GetLab().GetLabModel());
                    Text = @"Компилятор C mini - " + Lab.GetLab().FileName;
                    fs.Close();
                    saveLabLink.Enabled = true;
                    saveLabAsLink.Enabled = true;
                    menuLab.Enabled = true;
                }
            }
        }

        private void addToken_Click(object sender, EventArgs e)
        {
            var tokenEdit = new TokenEdit(tokensView);
            tokenEdit.ShowDialog(this);
        }

        private void editToken_Click(object sender, EventArgs e)
        {
            if (tokensView.SelectedItems.Count == 1)
            {
                var tokenEdit = new TokenEdit(tokensView, tokensView.SelectedItems[0]);
                tokenEdit.ShowDialog(this);
            }
        }

        private void deleteToken_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in tokensView.SelectedItems)
            {
                tokensView.Items.Remove(item);    
            }
        }

        private const string Reorder = "Reorder";

        private void tokensView_DragDrop(object sender, DragEventArgs e)
        {
            tokensView.Alignment = ListViewAlignment.Default;
            if (tokensView.SelectedItems.Count == 0)
            {
                return;
            }
            var cp = tokensView.PointToClient(new Point(e.X, e.Y));
            var dragToItem = tokensView.GetItemAt(cp.X, cp.Y);
            if (dragToItem == null)
            {
                return;
            }
            var dropIndex = dragToItem.Index;
            if (dropIndex > tokensView.SelectedItems[0].Index)
            {
                dropIndex++;
            }
            var insertItems = new List<ListViewItem>();
            foreach (ListViewItem item in tokensView.SelectedItems)
            {
                insertItems.Add((ListViewItem)item.Clone());
            }
            for (int i = insertItems.Count - 1; i >= 0; i--)
            {
                var insertItem = insertItems[i];
                tokensView.Items.Insert(dropIndex, insertItem);
            }
            foreach (ListViewItem removeItem in tokensView.SelectedItems)
            {
                tokensView.Items.Remove(removeItem);
            }
            tokensView.Alignment = ListViewAlignment.SnapToGrid;
        }

        private void tokensView_DragOver(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var cp = tokensView.PointToClient(new Point(e.X, e.Y));
            var hoverItem = tokensView.GetItemAt(cp.X, cp.Y);
            if (hoverItem == null)
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            foreach (ListViewItem moveItem in tokensView.SelectedItems)
            {
                if (moveItem.Index == hoverItem.Index)
                {
                    e.Effect = DragDropEffects.None;
                    hoverItem.EnsureVisible();
                    return;
                }
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            if (String.Compare(text, Reorder, StringComparison.Ordinal) == 0)
            {
                e.Effect = DragDropEffects.Move;
                hoverItem.EnsureVisible();
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void tokensView_DragEnter(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            e.Effect = String.Compare(text, Reorder, StringComparison.Ordinal) == 0 ? DragDropEffects.Move : DragDropEffects.None;
        }

        private void tokensView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            tokensView.DoDragDrop(Reorder, DragDropEffects.Move);
        }

        private void addId_Click(object sender, EventArgs e)
        {
            var idEdit = new IdEdit(idsView);
            idEdit.ShowDialog(this);
        }

        private void editId_Click(object sender, EventArgs e)
        {
            if (idsView.SelectedItems.Count == 1)
            {
                var idEdit = new IdEdit(idsView, idsView.SelectedItems[0]);
                idEdit.ShowDialog(this);
            }
        }

        private void deleteId_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in idsView.SelectedItems)
            {
                idsView.Items.Remove(item);
            }
        }

        private void addConst_Click(object sender, EventArgs e)
        {
            var constantEdit = new ConstantEdit(constantsView);
            constantEdit.ShowDialog(this);
        }

        private void editConst_Click(object sender, EventArgs e)
        {
            if (constantsView.SelectedItems.Count == 1)
            {
                var constantEdit = new ConstantEdit(constantsView, constantsView.SelectedItems[0]);
                constantEdit.ShowDialog(this);
            }
        }

        private void deleteConst_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in constantsView.SelectedItems)
            {
                constantsView.Items.Remove(item);
            }
        }

        private void idsView_DragDrop(object sender, DragEventArgs e)
        {
            idsView.Alignment = ListViewAlignment.Default;
            if (idsView.SelectedItems.Count == 0)
            {
                return;
            }
            var cp = idsView.PointToClient(new Point(e.X, e.Y));
            var dragToItem = idsView.GetItemAt(cp.X, cp.Y);
            if (dragToItem == null)
            {
                return;
            }
            var dropIndex = dragToItem.Index;
            if (dropIndex > idsView.SelectedItems[0].Index)
            {
                dropIndex++;
            }
            var insertItems = new List<ListViewItem>();
            foreach (ListViewItem item in idsView.SelectedItems)
            {
                insertItems.Add((ListViewItem)item.Clone());
            }
            for (int i = insertItems.Count - 1; i >= 0; i--)
            {
                var insertItem = insertItems[i];
                idsView.Items.Insert(dropIndex, insertItem);
            }
            foreach (ListViewItem removeItem in idsView.SelectedItems)
            {
                idsView.Items.Remove(removeItem);
            }
            idsView.Alignment = ListViewAlignment.Top;
        }

        private void idsView_DragEnter(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            e.Effect = String.Compare(text, Reorder, StringComparison.Ordinal) == 0 ? DragDropEffects.Move : DragDropEffects.None;
        }

        private void idsView_DragOver(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var cp = idsView.PointToClient(new Point(e.X, e.Y));
            var hoverItem = idsView.GetItemAt(cp.X, cp.Y);
            if (hoverItem == null)
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            foreach (ListViewItem moveItem in idsView.SelectedItems)
            {
                if (moveItem.Index == hoverItem.Index)
                {
                    e.Effect = DragDropEffects.None;
                    hoverItem.EnsureVisible();
                    return;
                }
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            if (String.Compare(text, Reorder, StringComparison.Ordinal) == 0)
            {
                e.Effect = DragDropEffects.Move;
                hoverItem.EnsureVisible();
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void idsView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            idsView.DoDragDrop(Reorder, DragDropEffects.Move);
        }

        private void constantsView_DragDrop(object sender, DragEventArgs e)
        {
            constantsView.Alignment = ListViewAlignment.Default;
            if (constantsView.SelectedItems.Count == 0)
            {
                return;
            }
            var cp = constantsView.PointToClient(new Point(e.X, e.Y));
            var dragToItem = constantsView.GetItemAt(cp.X, cp.Y);
            if (dragToItem == null)
            {
                return;
            }
            var dropIndex = dragToItem.Index;
            if (dropIndex > constantsView.SelectedItems[0].Index)
            {
                dropIndex++;
            }
            var insertItems = new List<ListViewItem>();
            foreach (ListViewItem item in constantsView.SelectedItems)
            {
                insertItems.Add((ListViewItem)item.Clone());
            }
            for (int i = insertItems.Count - 1; i >= 0; i--)
            {
                var insertItem = insertItems[i];
                constantsView.Items.Insert(dropIndex, insertItem);
            }
            foreach (ListViewItem removeItem in constantsView.SelectedItems)
            {
                constantsView.Items.Remove(removeItem);
            }
            constantsView.Alignment = ListViewAlignment.Top;
        }

        private void constantsView_DragEnter(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            e.Effect = String.Compare(text, Reorder, StringComparison.Ordinal) == 0 ? DragDropEffects.Move : DragDropEffects.None;
        }

        private void constantsView_DragOver(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var cp = constantsView.PointToClient(new Point(e.X, e.Y));
            var hoverItem = constantsView.GetItemAt(cp.X, cp.Y);
            if (hoverItem == null)
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            foreach (ListViewItem moveItem in constantsView.SelectedItems)
            {
                if (moveItem.Index == hoverItem.Index)
                {
                    e.Effect = DragDropEffects.None;
                    hoverItem.EnsureVisible();
                    return;
                }
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            if (String.Compare(text, Reorder, StringComparison.Ordinal) == 0)
            {
                e.Effect = DragDropEffects.Move;
                hoverItem.EnsureVisible();
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void constantsView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            constantsView.DoDragDrop(Reorder, DragDropEffects.Move);
        }

        private FileStream _fs;

        private void loadCodeLink_Click(object sender, EventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Filter = @"Файл кода программы C (*.c) | *.c",
                Title = @"Загрузка кода программы",
                Multiselect = false,
                ValidateNames = true
            };

            if (openFileDialog.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(openFileDialog.FileName)) return;

            var fs = (FileStream)openFileDialog.OpenFile();
            _fs = new FileStream(openFileDialog.FileName, FileMode.Open, FileAccess.Read);
            var sr = new StreamReader(fs);
            while (sr.Peek() >= 0)
            {
                Lab.GetLab().Code.Add(sr.ReadLine());
            }
            sr.Close();

            loadCodeLink.Enabled = false;
            checkCode.Visible = true;
            codeBox.Enabled = true;
            codePage.Text = @"Статический анализ кода";
            codeBox.TextAlign = HorizontalAlignment.Left;
            codeBox.ScrollBars = ScrollBars.Both;
            codeBox.Font = new Font("Consolas", 12F, FontStyle.Regular, GraphicsUnit.Point, 204);
            codeBox.Lines = Lab.GetLab().Code.ToArray();
        }

        private void checkCode_Click(object sender, EventArgs e)
        {
            Lab.GetLab().CompiledProgram = new CompiledProgram(_fs);
            if (Lab.GetLab().CompiledProgram.Errors.Count > 0)
            {
                errorsBox.Clear();
                errorsBox.Lines = Lab.GetLab().CompiledProgram.Errors.ToArray();
                MessageBox.Show(@"В ходе статического анализа кода были обнаружены ошибки. Отредактируйте код программы любым текстовым редактором.", @"Внимание");
                Lab.GetLab().StaticMistakes++;
                return;
            }
            DisableCodePage();
            EnableLexicalPage();
            if (Lab.GetLab().Code.Count > 0)
            {
                loadCodeLink.Enabled = false;
            }
            codeLexicalBox.Lines = codeBox.Lines;
            Lab.GetLab().StaticComplete = true;
            MessageBox.Show(@"Статический анализ кода успешно завершен. Лексический анализ доступен для выполнения", @"Сообщение");
            _fs.Close();
        }

        private int GetIndexByTypeName(string typeName)
        {
            switch (typeName)
            {
                case "void":
                    return 0;
                case "int":
                    return 1;
                case "bool":
                    return 2;
                default:
                    return -1;
            }
        }

        private int GetIndexByLevelName(string levelName)
        {
            switch (levelName)
            {
                case "Глобальный":
                    return 0;
                case "Локальный":
                    return 1;
                default:
                    return -1;
            }
        }

        private void checkLexical_Click(object sender, EventArgs e)
        {
            // Проверка
            var tokensStream = new List<Lexem>();
            foreach (ListViewItem item in tokensView.Items)
            {
                tokensStream.Add(new Lexem(item.Text, item.ImageIndex));
            }
            var identifiers = new List<Variable>();
            foreach (ListViewItem item in idsView.Items)
            {
                identifiers.Add(new Variable(item.SubItems[1].Text, GetIndexByTypeName(item.SubItems[2].Text), GetIndexByLevelName(item.SubItems[3].Text)));
            }
            var constants = new List<Constant>();
            foreach (ListViewItem item in constantsView.Items)
            {
                constants.Add(new Constant(item.SubItems[1].Text));
            }
            if (tokensStream.Count == Lab.GetLab().CompiledProgram.LexicalTables.lexemTable.Count)
            {
                for (int i = 0; i < tokensStream.Count; i++)
                {
                    if (!tokensStream[i].Equals(Lab.GetLab().CompiledProgram.LexicalTables.lexemTable[i]))
                    {
                        MessageBox.Show(@"Неверный поток токенов.", @"Внимание");
                        Lab.GetLab().LexicalMistakes++;
                        return;
                    }
                }
            }
            else
            {
                MessageBox.Show(@"Неверное количество токенов.", @"Внимание");
                Lab.GetLab().LexicalMistakes++;
                return;
            }

            if (identifiers.Count == Lab.GetLab().CompiledProgram.LexicalTables.variableTable.Count)
            {
                for (int i = 0; i < identifiers.Count; i++)
                {
                    if (!identifiers[i].Equals(Lab.GetLab().CompiledProgram.LexicalTables.variableTable[i]))
                    {
                        MessageBox.Show(@"Обнаружены ошибки в таблице идентификаторов.", @"Внимание");
                        Lab.GetLab().LexicalMistakes++;
                        return;
                    }
                }
            }
            else
            {
                MessageBox.Show(@"Неверное количество идентификаторов.", @"Внимание");
                Lab.GetLab().LexicalMistakes++;
                return;
            }

            if (constants.Count == Lab.GetLab().CompiledProgram.LexicalTables.constantTable.Count)
            {
                for (int i = 0; i < constants.Count; i++)
                {
                    if (!constants[i].Equals(Lab.GetLab().CompiledProgram.LexicalTables.constantTable[i]))
                    {
                        MessageBox.Show(@"Обнаружены ошибки в таблице констант.", @"Внимание");
                        Lab.GetLab().LexicalMistakes++;
                        return;
                    }
                }
            }
            else
            {
                MessageBox.Show(@"Неверное количество констант.", @"Внимание");
                Lab.GetLab().LexicalMistakes++;
                return;
            }

            MessageBox.Show(@"Лексический анализ успешно завершен. Синтаксический анализ доступен для выполнения.", @"Сообщение");
            DisableLexicalPage();
            EnableSyntaxPage();
            Lab.GetLab().LexicalComplete = true;
            tokensViewOnly.Items.Clear();
            foreach (ListViewItem item in tokensView.Items)
            {
                tokensViewOnly.Items.Add((ListViewItem) item.Clone());
            }
            constantsViewOnly.Items.Clear();
            foreach (ListViewItem item in constantsView.Items)
            {
                constantsViewOnly.Items.Add((ListViewItem)item.Clone());
            }
            identsViewOnly.Items.Clear();
            foreach (ListViewItem item in idsView.Items)
            {
                identsViewOnly.Items.Add((ListViewItem)item.Clone());
            }
        }

        private void saveLabLink_Click(object sender, EventArgs e)
        {
            if (File.Exists(Lab.GetLab().FileName))
            {
                var fs = new FileStream(Lab.GetLab().FileName, FileMode.Open, FileAccess.Write);
                var bf = new BinaryFormatter();
                AssemblyLabModel();
                bf.Serialize(fs, Lab.GetLab());
                fs.Close();
            }
            else
            {
                saveLabAsLink_Click(sender, e);
            }
        }

        private void labResultsLink_Click(object sender, EventArgs e)
        {
            var resultsForm = new ResultsForm();
            resultsForm.ShowDialog(this);
        }

        private void addBranch_Click(object sender, EventArgs e)
        {
            if (treeBuilder.SelectedNode == null)
            {
                MessageBox.Show(@"Выделите ветвь или корень", @"Сообщение");
            }
            else
            {
                var branchEdit = new BranchEdit(treeBuilder);
                branchEdit.ShowDialog(this);
            }
        }

        private void deleteBranch_Click(object sender, EventArgs e)
        {
            if (treeBuilder.SelectedNode != null) {
                if (treeBuilder.SelectedNode.Parent != null)
                {
                    treeBuilder.SelectedNode.Remove();
                }
            }
        }

        private void editBranch_Click(object sender, EventArgs e)
        {
            if (treeBuilder.SelectedNode != null) {
                if (treeBuilder.SelectedNode.Parent != null)
                {
                    var branchEdit = new BranchEdit(treeBuilder, treeBuilder.SelectedNode);
                    branchEdit.ShowDialog(this);
                }
            }
        }

        private string GetNodeName(string text)
        {
            return text.Split(':')[0];
        }

        private string GetNodeValue(string text)
        {
            return text.Split(':').Length > 1 ? text.Split(':')[1].Trim() : "";
        }

        private void AddChildSyntaxNode(TreeNode node, SyntaxNode parentNode)
        {
            var newSyntaxNode = new SyntaxNode(GetNodeName(node.Text), GetNodeValue(node.Text), parentNode);
            parentNode.ChildNodes.Add(newSyntaxNode);

            foreach (TreeNode treeNode in node.Nodes)
            {
                AddChildSyntaxNode(treeNode, newSyntaxNode);
            }
        }

        private void AddChildTreeNode(SyntaxNode node, TreeNode parentNode)
        {
            var newTreeNode = new TreeNode(node.NodeName + ": " + node.NodeVal);
            parentNode.Nodes.Add(newTreeNode);

            foreach (SyntaxNode syntaxNode in node.ChildNodes)
            {
                AddChildTreeNode(syntaxNode, newTreeNode);
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            // Проверка
            var root = new SyntaxNode(GetNodeName(treeBuilder.Nodes[0].Text), GetNodeValue(treeBuilder.Nodes[0].Text), null);
            foreach (TreeNode treeNode in treeBuilder.Nodes[0].Nodes)
            {
                AddChildSyntaxNode(treeNode, root);
            }
            if (!root.Equals(Lab.GetLab().CompiledProgram.SyntaxTreeRoot))
            {
                MessageBox.Show(@"Обнаружены ошибки в дереве синтаксического разбора.", @"Внимание");
                Lab.GetLab().SyntaxMistakes++;
                return;
            }
            MessageBox.Show(@"Синтаксический анализ успешно завершен. Генерация кода доступна для выполнения.", @"Сообщение");
            DisableSyntaxPage();
            EnableTetradesPanel();
            treeView.Nodes.Clear();
            foreach (TreeNode treeNode in treeBuilder.Nodes)
            {
                treeView.Nodes.Add((TreeNode) treeNode.Clone());
            }
            foreach (TreeNode treeNode in treeView.Nodes)
            {
                treeNode.ExpandAll();
            }
            Lab.GetLab().SyntaxComplete = true;
        }

        private void addTetrade_Click(object sender, EventArgs e)
        {
            var tetradeEdit = new TetradeEdit(tetradesView);
            tetradeEdit.ShowDialog(this);
        }

        private void editTetrade_Click(object sender, EventArgs e)
        {
            if (tetradesView.SelectedItems.Count == 1)
            {
                var tetradeEdit = new TetradeEdit(tetradesView, tetradesView.SelectedItems[0]);
                tetradeEdit.ShowDialog(this);
            }
        }

        private void deleteTetrade_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in tetradesView.SelectedItems)
            {
                tetradesView.Items.Remove(item);
            }
        }

        private void tetradesView_DragDrop(object sender, DragEventArgs e)
        {
            tetradesView.Alignment = ListViewAlignment.Default;
            if (tetradesView.SelectedItems.Count == 0)
            {
                return;
            }
            var cp = tetradesView.PointToClient(new Point(e.X, e.Y));
            var dragToItem = tetradesView.GetItemAt(cp.X, cp.Y);
            if (dragToItem == null)
            {
                return;
            }
            var dropIndex = dragToItem.Index;
            if (dropIndex > tetradesView.SelectedItems[0].Index)
            {
                dropIndex++;
            }
            var insertItems = new List<ListViewItem>();
            foreach (ListViewItem item in tetradesView.SelectedItems)
            {
                insertItems.Add((ListViewItem)item.Clone());
            }
            for (int i = insertItems.Count - 1; i >= 0; i--)
            {
                var insertItem = insertItems[i];
                tetradesView.Items.Insert(dropIndex, insertItem);
            }
            foreach (ListViewItem removeItem in tetradesView.SelectedItems)
            {
                tetradesView.Items.Remove(removeItem);
            }
            tetradesView.Alignment = ListViewAlignment.Top;
        }

        private void tetradesView_DragEnter(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            e.Effect = String.Compare(text, Reorder, StringComparison.Ordinal) == 0 ? DragDropEffects.Move : DragDropEffects.None;
        }

        private void tetradesView_DragOver(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.Text))
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            var cp = tetradesView.PointToClient(new Point(e.X, e.Y));
            var hoverItem = tetradesView.GetItemAt(cp.X, cp.Y);
            if (hoverItem == null)
            {
                e.Effect = DragDropEffects.None;
                return;
            }
            foreach (ListViewItem moveItem in tetradesView.SelectedItems)
            {
                if (moveItem.Index == hoverItem.Index)
                {
                    e.Effect = DragDropEffects.None;
                    hoverItem.EnsureVisible();
                    return;
                }
            }
            var text = (String)e.Data.GetData(Reorder.GetType());
            if (String.Compare(text, Reorder, StringComparison.Ordinal) == 0)
            {
                e.Effect = DragDropEffects.Move;
                hoverItem.EnsureVisible();
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void tetradesView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            tetradesView.DoDragDrop(Reorder, DragDropEffects.Move);
        }

        private void checkTetrades_Click(object sender, EventArgs e)
        {
            // Проверка
            var tetrades = new List<Tetrade>();
            foreach (ListViewItem item in tetradesView.Items)
            {
                tetrades.Add(new Tetrade(item.Text, item.SubItems[1].Text, item.SubItems[2].Text, item.SubItems[3].Text));
            }

            if (tetrades.Count == Lab.GetLab().CompiledProgram.CodeGen.TetradeList.Count)
            {
                for (int i = 0; i < tetrades.Count; i++)
                {
                    if (!tetrades[i].Equals(Lab.GetLab().CompiledProgram.CodeGen.TetradeList[i]))
                    {
                        MessageBox.Show(@"В таблице тетрад обнаружены ошибки", @"Внимание");
                        Lab.GetLab().GenerationMistakes++;  // Ошибки нашего поколения
                        return;
                    }
                }
            }
            else
            {
                MessageBox.Show(@"Неверное количество тетрад", @"Внимание");
                Lab.GetLab().GenerationMistakes++;  // Ошибки нашего поколения
                return;
            }
            MessageBox.Show(@"Генерация кода успешно завершена. Компиляция программы окончена.", @"Сообщение");
            DisableTetradesPanel();
            Lab.GetLab().GenerationComplete = true;
        }

        private void authorsLink_Click(object sender, EventArgs e)
        {
            var authorsForm = new AuthorsForm();
            authorsForm.ShowDialog(this);
        }
    }
}
